package br.unisinos.handler;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.util.ArrayList;

import br.lp2p.commons.LP2PInternalMessages;
import br.unisinos.arquivos.DirectoryEntry;
import br.unisinos.arquivos.FileShared;

public class Handler implements Runnable {

	private Socket clntSock;
	private ArrayList<DirectoryEntry> entries = null;

	public Handler(Socket clntSock, ArrayList<DirectoryEntry> entries) {
		this.clntSock = clntSock;
		this.entries = entries;
	}

	@Override
	public void run() {
		byte[] bBuffer = new byte[LP2PInternalMessages.MSG_BUFLEN];

		try {
			InputStream in = clntSock.getInputStream();
			OutputStream out = clntSock.getOutputStream();

			in.read(bBuffer);

			byte[] resp = processMessage(bBuffer);

			out.write(resp);
			// System.out.println(new String(resp));
		} catch (IOException ioex) {
			ioex.printStackTrace();
		} finally {
			try {
				clntSock.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

	}

	public byte[] processMessage(byte[] byteBuffer) {
		StringBuilder tmpResp = new StringBuilder();
		ByteBuffer resp = null;
		int respLen;

		// for (int i=0; i<4; i++)
		// protocol.append((char) byteBuffer[i]);

		byte op = byteBuffer[6];

		switch (op) {
		case LP2PInternalMessages.LP2P_LLIST:
			// received a list message
			int i = 0;

			for (i = 7; i < byteBuffer.length; i++) {
				char tmp = (char) byteBuffer[i];
				if (tmp != LP2PInternalMessages.DELIM)
					tmpResp.append(tmp);
				else
					break;
			}

			// generate response
			String files = null;
			int numLocalFiles = 0;
			for (DirectoryEntry entry : entries) {
				if (tmpResp.toString().equals(entry.getRelativeDirName())) {
					files = entry.getFormatedShare();
					numLocalFiles = entry.getNumFiles();
					break;
				}
			}

			tmpResp.append(LP2PInternalMessages.DELIM);
			tmpResp.append(numLocalFiles);
			tmpResp.append(LP2PInternalMessages.DELIM);

			if (files != null)
				tmpResp.append(files);
			// System.out.println("Files found: " + tmpResp.toString());

			resp = ByteBuffer.allocateDirect(7 + tmpResp.length());

			resp.put("LP2P".getBytes());
			resp.put((byte) 1);
			resp.put((byte) 1);
			resp.put(LP2PInternalMessages.LP2P_LSENDL);
			resp.put(tmpResp.toString().getBytes());

			break;
		case LP2PInternalMessages.LP2P_LGET:
			// received a get message
			// System.out.println("Received a get message!");

			int j = 0;
			int k = 0;
			int dataLen = 0;
			long fileId;
			long offset;
			long length;
			byte[] data = null;
			StringBuilder sb = new StringBuilder();

			// get sharing name
			for (j = 7; j < byteBuffer.length; j++) {
				char tmp = (char) byteBuffer[j];
				if (tmp != LP2PInternalMessages.DELIM)
					tmpResp.append(tmp);
				else
					break;
			}

			// get fileID
			j++;
			for (k = j; k < byteBuffer.length; k++) {
				char tmp = (char) byteBuffer[k];
				if (tmp != LP2PInternalMessages.DELIM)
					sb.append(tmp);
				else
					break;
			}
			fileId = Long.parseLong(sb.toString());

			// get offset
			j = k + 1;
			sb = new StringBuilder();

			for (k = j; k < byteBuffer.length; k++) {
				char tmp = (char) byteBuffer[k];
				if (tmp != LP2PInternalMessages.DELIM)
					sb.append(tmp);
				else
					break;
			}
			offset = Long.parseLong(sb.toString());

			// get length
			j = k + 1;
			sb = new StringBuilder();
			for (k = j; k < byteBuffer.length; k++) {
				char tmp = (char) byteBuffer[k];
				if (tmp != LP2PInternalMessages.DELIM)
					sb.append(tmp);
				else
					break;
			}
			length = Long.parseLong(sb.toString());

			FileShared file = null;
			for (DirectoryEntry entry : entries) {
				if (tmpResp.toString().equals(entry.getRelativeDirName())) {
					file = entry.getSelectedFile(fileId);
					break;
				}
			}

			// generate response
			tmpResp.append(LP2PInternalMessages.DELIM);

			if (file != null) {
				data = file.getData(offset, length);
				if (data != null)
					dataLen = data.length;
				else
					dataLen = 0;
			} else {
				data = null;
				dataLen = 0;
			}

			tmpResp.append(fileId);
			tmpResp.append(LP2PInternalMessages.DELIM);
			tmpResp.append(offset);
			tmpResp.append(LP2PInternalMessages.DELIM);
			tmpResp.append(dataLen);
			tmpResp.append(LP2PInternalMessages.DELIM);

			// System.out.println("Answer without data: " + tmpResp.toString());

			respLen = 7 + tmpResp.length() + dataLen;
			resp = ByteBuffer.allocateDirect(respLen);
			resp.put("LP2P".getBytes());
			resp.put((byte) 1);
			resp.put((byte) 1);
			resp.put(LP2PInternalMessages.LP2P_LSENDF);
			resp.put(tmpResp.toString().getBytes());

			if (dataLen > 0)
				resp.put(data);
			break;
		}

		resp.flip();

		byte[] tmpArray = new byte[resp.limit()];
		resp.get(tmpArray);

		return tmpArray;
	}

}
